<script setup lang="ts">
import { getCurrentInstance, reactive, ref } from 'vue';
import { VueCropper } from 'vue-cropper';
import 'vue-cropper/dist/index.css';

import { ElMinus, ElPlus, ElRefreshLeft, ElRefreshRight } from '@vben/icons';

import { StorageManager } from '@vben-core/shared/cache';

import {
  ElButton,
  ElCol,
  ElDialog,
  ElMessage,
  ElRow,
  ElUpload,
} from 'element-plus';

import { avatar } from '../assets';

const props = defineProps({
  dialogVisibleCropper: {
    type: Boolean,
    default: false,
  },
});

const emit = defineEmits(['update:dialogVisibleCropper', 'confirm']);

const storageManager = new StorageManager({
  prefix: '',
  storageType: 'sessionStorage',
});

const realAvatar = ref(
  storageManager.getItem('avatar')
    ? `${storageManager.getItem('avatar')}`
    : avatar,
);
const { proxy } = getCurrentInstance();
const showCropper = ref(false);
// cropper配置  更多配置可参考 https://www.npmjs.com/package/vue-cropper
const options = reactive({
  img: realAvatar.value, // 裁剪图片的地址
  autoCropWidth: 200, // 默认生成截图框宽度 默认容器的 80%
  autoCropHeight: 200, // 默认生成截图框高度 默认容器的 80%
  outputType: 'png', // 裁剪生成图片的格式 jpeg, png, webp
  autoCrop: true, // 是否默认生成截图框
  fixedBox: false, // 固定截图框大小
});
const previews = ref({
  url: '',
  img: '',
});
// 打开裁剪弹窗
const openDialog = () => {
  showCropper.value = true;
};
// 修改图片大小 正数为变大 负数变小
const changeScale = (num: number = 1) => {
  proxy.$refs.cropper.changeScale(num);
};
// 向左边旋转90度
const rotateLeft = () => {
  proxy.$refs.cropper.rotateLeft();
};
// 向右边旋转90度
const rotateRight = () => {
  proxy.$refs.cropper.rotateRight();
};
// 上传图片处理
const beforeUpload = (rawFile: File) => {
  if (!rawFile.type.includes('image/')) {
    ElMessage.error('请上传图片类型文件!');
    return false;
  }
  if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error('文件大小不能超过2MB!');
    return false;
  }
  const reader = new FileReader();
  reader.readAsDataURL(rawFile);
  reader.addEventListener('load', () => {
    // 图片在这里
    options.img = reader.result;
  });
};
// 实时预览事件
const realTime = (data: any) => {
  previews.value = data;
};
const cropper = ref();
// 关闭弹窗
const beforeClose = () => {
  // options.img = null
  // previews.value.url = ''
  emit('update:dialogVisibleCropper', false);
};
const croppedFile = ref(null);

// 提交图片
const determine = () => {
  cropper.value.getCropData((data) => {
    // 将裁剪后的图片数据转换为文件对象
    const file = base64ToFile(data, 'image.png');
    croppedFile.value = file;
    emit('confirm', file); // 将文件对象通过事件传递给父组件
  });
};

function base64ToFile(base64Data, fileName) {
  const arr = base64Data.split(',');
  const mime = arr[0].match(/:(.*?);/)[1];
  const bstr = atob(arr[1]);
  let n = bstr.length;
  const u8arr = new Uint8Array(n);

  while (n--) {
    u8arr[n] = bstr.codePointAt(n) as number;
  }

  return new File([u8arr], fileName, { type: mime });
}
</script>

<template>
  <div class="avatar-container">
    <ElDialog
      :title="$t('page.profile.editAvatar')"
      :model-value="props.dialogVisibleCropper"
      width="800px"
      append-to-body
      @opened="openDialog"
      destroy-on-close
      :before-close="beforeClose"
      draggable
    >
      <ElRow>
        <ElCol :span="12" style="height: 300px">
          <VueCropper
            ref="cropper"
            :img="options.img"
            :info="true"
            :auto-crop="options.autoCrop"
            :auto-crop-width="options.autoCropWidth"
            :auto-crop-height="options.autoCropHeight"
            :fixed-box="options.fixedBox"
            :output-type="options.outputType"
            @real-time="realTime"
            v-if="showCropper"
          />
        </ElCol>
        <ElCol :span="12" style="height: 300px">
          <div class="preview-box">
            <img
              v-if="previews.url"
              :src="previews.url"
              :style="previews.img"
            />
            <span v-else></span>
          </div>
        </ElCol>
      </ElRow>
      <template #footer>
        <span class="dialog-footer">
          <ElRow style="margin-top: 12px">
            <ElCol :span="12">
              <ElRow>
                <ElCol :span="8">
                  <ElUpload
                    action="#"
                    :http-request="() => {}"
                    :before-upload="beforeUpload"
                    :show-file-list="false"
                  >
                    <ElButton>{{ $t('page.profile.chooseFile') }}</ElButton>
                  </ElUpload>
                </ElCol>
                <ElCol :span="4">
                  <ElButton :icon="ElPlus" @click="changeScale(1)" />
                </ElCol>
                <ElCol :span="4">
                  <ElButton :icon="ElMinus" @click="changeScale(-1)" />
                </ElCol>
                <ElCol :span="4">
                  <ElButton :icon="ElRefreshLeft" @click="rotateLeft()" />
                </ElCol>
                <ElCol :span="4">
                  <ElButton :icon="ElRefreshRight" @click="rotateRight()" />
                </ElCol>
              </ElRow>
            </ElCol>
            <ElCol :span="4" :offset="8" style="margin-left: 22.3%">
              <ElButton class="mybtn" type="primary" @click="determine()">{{
                $t('page.profile.submit')
              }}</ElButton>
            </ElCol>
          </ElRow>
        </span>
      </template>
    </ElDialog>
  </div>
</template>

<style lang="scss" scoped>
.avatar-container {
  .img-box {
    width: 10vw;
    height: 10vw;
    border: 1px solid #ccc;
    border-radius: 50%;
  }
}

.preview-box {
  position: absolute;
  top: 50%;
  width: 200px;
  height: 200px;
  overflow: hidden;
  border: 1px solid #ccc;
  border-radius: 50%;
  transform: translate(50%, -50%);
}

.mybtn {
  width: 80px;
  height: 30px;
  font-weight: bolder;
  letter-spacing: 1px;
  border-radius: 3px;
}
</style>
